/*
 * @Author: lsmi
 * @Date: 2021-11-03 20:30:29
 * @LastEditors: lsmi
 * @LastEditTime: 2021-11-18 22:14:10
 * @FilePath: \base-typescript\src\index2.ts
 */
function a1() {

}
// 类型进阶
// 子类型和超类型
// 子类型  给定两个类型A和B，假如B是A的子类型，那么在需要A的地方都可以放心使用B （A包含B）
// 这里可以查看P27
// Array是Object的子类型 Tuple(元组)是Array的子类型 所有类型都是any的子类型(除了unknown) never是所有类型的子类型
// 如果Bird类扩展自Animal类，那么Bird是Animal的子类型
// never看在任何地方使用

// 超类型于子类型相反
// 给定两个类型A和B，假如B是A的超类型，那么在需要B的地方都可以放心使用A（B包含A）

// 型变 有 不变 只能是T 协变 可以是<:T  逆变 可以是>:T  双变  可以是<:T或>:T

// 引用一套句法
// A <: B 指 A类型是B类型的子类型， 或者为同种类型
// A >: B 指 A类型是B类型的超类型, 或者为同类型

// 函数型变
// 如果函数A的参数数量小于或等于函数B的参数数量，而且满足下述条件，那么函数A是函数B的子类型:
// 1. 函数A的this类型未指定，或者>:函数B的this类型
// 2. 函数A的各个参数的类型>:函数B的相应参数类型
// 3. 函数A的返回类型<:函数B的返回类型


// 类型拓宽
// 类型拓宽是理解TypeScript类型推导机制的关键。一般来说，TypeScript在推导类型时会放宽要求，故意推导出一个更宽泛的类型，而不限定为
// 某个具体的类型。这样做对程序员是有好处的，大大减少了消除类型检查器报错的时间

// 类型拓宽
let ac1 = 'x' // string
let bc1 = 3 // number
var cc1 = false // boolean
const dc1 = { x: 3 } // { x: number }
enum E { X, Y, Z }
let e2 = E.X // E

// 不可变变量
const e1 = E.X // E.X
const ac2 = '3' // '3'

let ac3 = null // any
ac3 = 3 // any
ac3 = 'b' // any

// 细化
// TypeScript采用的是基于流的类型推导，这是一种符号执行，类型检查器在检查代码的过程中利用流程语句(如if、？、||和switch)
// 和类型查询(typeof、instanceof和in)细化类型，就像程序员阅读代码的流程一样

// keyof 运算符
type APIRes = {
  user: {
    id: string
  },
  name: string,
  object: object
}
type Res = keyof { name: string } // name

// T是any的子类型  K 是 keyof T的子类型   keyof T = 'user' | 'name' | 'object'  所以K可以是 'user','name','object'
type Res1<T extends any, K extends keyof T> = K
let res1: Res1<APIRes, 'name' | 'object'> = "name"


// 映射类型
type Str = "name" | "age" | "id" | "ip"

// type StrFu = {
//   [K in Str]: any
// }
type StrFn<T extends keyof APIRes> = {
  [K in T]: any
}
let ya: StrFn<'name'> = {
  name: 'x'
}

type StrFn1<T extends keyof any, U> = {
  [K in T]: U
}
let ya1: StrFn1<'name' | 'age', any> = {
  name: 'x',
  age: 1
}


// 条件类型
// 在TypeScript的众多特效中，条件类型算是独特的。概括地说，条件类型表达的是，“声明一个依赖类型U和V的类型T，如果U<:V，把T赋值给A；否则把T赋值给B
type IsString<T> = T extends string ? true : false
type A = IsString<string> // true

type ToArray2<T> = T extends any ? T[] : any
type AA= ToArray2<number | string>



// infer关键字
// T 是 any[]的子类型 说明T是数组或元组  T[number] 就是之前的句法 获取T[index]的类型
// 为了获取any的类型 any就对应了T[number]的类型  所以可以使用 infer
type ElementType12<T> = T extends any[] ? T[number] : any
type ElementType13<T> = T extends (infer U)[] ? U : any
// type AEl = ElementType12<[string, number]>
type AEL = ElementType13<[string, number, boolean]> // string | number | boolean

type MyExclude11 = keyof number | string | boolean // 为什么不能分配number
let ay:MyExclude11 = false
type MyExclude1<T, U> = T extends U ? never : T
type CI = MyExclude1<number|string, number>


// 实现 Non
// type ACS = { a?: number | null | string }
// type Non<T> = T extends null | undefined ? never : T
// type BCS = Non<ACS['a']> // number

// 实现Ret
type FAC = (a: number) => boolean
type Ret<T extends (...args: any) => any> = T extends (...args: any) => (infer U) ?  U : any
type RAC = Ret<FAC> //string


// 实现Ins
type ACS = { 
  new(): BCS
  new(): boolean
  new(): BCSC
}
type BCS = { b: number }
type BCSC = { b: string }
type Ins<T extends new(...args: any) => any> = T extends new(...args: any) => (infer B) ? B : any
type ICS = Ins<ACS> // { b: number }

// 模拟名义类型
type CompanyId = string 
type OrderId = string
type UserId = string
type Id = CompanyId | OrderId | UserId
function queryForUser(id: UserId){}

let id: CompanyId = 'b4843361'
queryForUser(id) // 这就是问题 需要UserId  但是传了CompanyId

// 要给这些Id加上类型烙印
type CompanyID = string & { readonly brand: unique symbol }
type OrderID = string & { readonly brand: unique symbol }
type UserID = string & { readonly brand: unique symbol }
type ID = CompanyID | OrderID | UserID


function CompanyID(id: string){
  return id as CompanyID
}
function queryForUsers(id: UserID){}
let companyId = CompanyID('8sa458d4')
let orderId = '4q48we8' as OrderID
let userId = 'base414w82' as UserID
queryForUsers(userId)
// queryForUsers(companyId) // 报错

// import './zip'
// let aP = [1,2,3]
// aP.zip




// type Exclusive<T, U> = T extends U ? T & U : never 
// T extends U ? never : T;
// Exclude<T, U> | Exclude<U, T>
type Exclusive<T, U> = (T extends U ? never : T) | (U extends T ? never : U);
type EPA = Exclusive<1 | 2 | 3, 2 | 3 | 4>
// 1 2 > 1
// 1 3 > 1
// 1 4 > 1
// 2 2 > never
// 2 3 > 2
// 2 4 > 2
// 3 2 > 3
// 3 3 > never
// 3 4 > 3

// 2 1 > 2
// 2 2 > never
// 2 3 > 2
// 3 1 > 3
// 3 2 > 3
// 3 3 > never
// 4 1 > 4
// 4 2 > 4
// 4 3 > 4
// (1 extends 2 | 4 ? never : 1) | (2 extends 2 | 4 ? never : 2) | (2 extends 1 | 2 ? never : 2) | (4 extends 1 | 2 ? never : 4)
// never | 
/*
  1. Start with Exclusive<1 | 2, 2 | 4>
  2. Substitute. Exclude<1 | 2, 2 | 4> | Exclude<2 | 4, 1 | 2>
  3. Substitute. (1 | 2 extends 2 | 4 ? never : 1 | 2) | (2 | 4 extends 1 | 2 ? never : 2 | 4)
  4. Distribute. (1 extends 2 | 4 ? never : 1) | (2 extends 2 | 4 ? never : 2) | (2 extends 1 | 2 ? never : 2) | (4 extends 1 | 2 ? never : 4)
  5. Simplify. 1 | never | never | 4
  6. Simplify. 1 | 4
*/

// (1 | 2 extends 2 | 4 ? never : 1 | 2) | (2 | 4 extends 1 | 2 ? never : 2 | 4)



